package common.dao.elastic;

import common.helper.toolkit.FileToolkit;
import org.bson.Document;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.client.AdminClient;
import org.elasticsearch.client.ClusterAdminClient;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.transport.TransportClient;
//import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by julianzliu on 2016/7/3.
 */
public class ElasticAdministratorTransHelper {

    static final Logger logger = LoggerFactory.getLogger(ElasticAdministratorTransHelper.class);

    public TransportClient esClient;
    private AdminClient adminClient;
    private IndicesAdminClient indicesClient;
    private ClusterAdminClient clusterClient;


    public ElasticAdministratorTransHelper(){

    }

    public ElasticAdministratorTransHelper(String tcpPath){
        //this.esClient = esDao.getESClient();
        this.esClient = createTransportClient(tcpPath);
        if(this.esClient != null) logger.info("Connected with Elasticsearch");
        if(this.esClient == null) logger.warn("can not establish Connnection with Elasticsearch");
        this.adminClient = this.esClient.admin();
        this.indicesClient = this.esClient.admin().indices();
        this.clusterClient = this.esClient.admin().cluster();
    }

    @Override
    protected void finalize(){
        try {
            super.finalize();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        //this.esClient.close();
        //logger.info("[finalize] close es client");
    }


    /*

    https://www.elastic.co/guide/en/elasticsearch/reference/2.1/breaking_20_java_api_changes.html

     */



    public TransportClient getTransportClient(String cluster_name, String host, Integer port){

        Settings settings = Settings.settingsBuilder()
                .put("cluster.name" , cluster_name)
                .put("client.transport.sniff", true)  //sniff other nodes
                .build();
        TransportClient esClient = TransportClient.builder().settings(settings).build();

        InetAddress tcp_host = null;

        try {
            tcp_host = InetAddress.getByName(host);
        }catch (Exception e){
            e.printStackTrace();
        }

        esClient.addTransportAddress(new InetSocketTransportAddress(tcp_host, port));

        return esClient;

    }




    public TransportClient getTransportClient(){
        return this.esClient;
    }

    public TransportClient createTransportClient(String filePath) {
        String json = FileToolkit.readStringFromFile(filePath);
        Document bson = Document.parse(json);
        String cname = bson.getString("cluster_name");
        if(cname == null){
            logger.warn("No Elasticsearch cluster name was specified!\n");
        }
        Settings settings = Settings.settingsBuilder()
                .put("cluster.name" , cname)
                .put("client.transport.sniff", true)  //sniff other nodes
                .build();
        TransportClient esClient = TransportClient.builder().settings(settings).build();
        setTransportAddress(esClient,filePath);
        return esClient;
    }

    private void setTransportAddress(TransportClient esClient, String filePath){
        String json = FileToolkit.readStringFromFile(filePath);
        logger.debug("TCP Address : \n {}",json);
        Document bson = Document.parse(json);
        List<Document> servers = (List<Document>) bson.get("servers");
        //可以添加多个节点
        //https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html
        if(servers != null) {
            for(Document server : servers) {
                String host = server.getString("host");
                InetAddress tcp_host = null;
                try{
                    tcp_host = InetAddress.getByName(host);
                }
                catch (UnknownHostException ex){
                    ex.printStackTrace();
                }
                Integer port = server.getInteger("port");
                if(host!=null && port!=null)
                    logger.info("[setTransportAddress] host = " + host + " , port = " + port);
                esClient.addTransportAddress(new InetSocketTransportAddress(tcp_host, port));
            }
        }
        else{
            logger.warn("No Elasticsearch Node was specified!\n");
        }
    }


    public boolean is_index_exist(String index){
        boolean exists = this.esClient.admin().indices()
                .prepareExists(index)
                .execute().actionGet().isExists();
        logger.info("[is_index_exist] = {}", exists);
        return exists;
    }


    public void createIndex(String index){
        Settings indexSettings = Settings.settingsBuilder()
                .put("number_of_shards", 3)
                .put("number_of_replicas", 1)
                .put("refresh_interval", "3s")
                .build();
        CreateIndexRequest indexRequest = new CreateIndexRequest(index, indexSettings);
        this.indicesClient.create(indexRequest);
        logger.info("[createIndex] index = {}" , index);
    }

    public void openIndex(String index){
        OpenIndexRequest indexRequest = new OpenIndexRequest(index);
        this.indicesClient.open(indexRequest);
        logger.info("[openIndex] index = {}" , index);
    }


    public void closeIndex(String index){
        CloseIndexRequest indexRequest = new CloseIndexRequest(index);
        this.indicesClient.close(indexRequest);
        logger.info("[closeIndex] index = {}" , index);
    }

    public void aliasIndex(String index, String alias){
        // https://github.com/elastic/elasticsearch/issues/2434
        this.indicesClient.prepareAliases()
                .removeAlias(index, alias)
                .addAlias(index, alias)
                .execute().actionGet();
        logger.info("[aliasIndex] index = {}, alias = {}" , index, alias);
    }

    public List<String> findAlias(String index){
        // http://stackoverflow.com/questions/31170105/elasticseach-java-api-to-find-aliases-given-index
        List<String> aliases = new ArrayList<>();
        return aliases;
    }

    public void setAnalysis(String index, String file_path){
        String json = FileToolkit.readStringFromFile(file_path);
        setAnalysisByJson(index, json);
    }


    public void setAnalysisByJson(String index, String json_string){
        // http://stackoverflow.com/questions/30434422/how-to-add-analyzer-settings-in-elasticsearch
        this.indicesClient
                .prepareCreate(index)
                .setSettings(json_string)
                .get();
        logger.info("[setAnalysis] index = {} , analysis = \n{}", index, json_string);

    }

    public void setMappingByJson(String index, String json_string){
        // http://stackoverflow.com/questions/22071198/adding-mapping-to-a-type-from-java-how-do-i-do-it

    }






    /**************************************************************
     *
     * @param esClient
     * @param filePath
     */
    private static void setTransportAddressStatic(TransportClient esClient, String filePath){
        String json = FileToolkit.readStringFromFile(filePath);
        logger.debug("TCP Address : \n {}",json);
        Document bson = Document.parse(json);
        List<Document> servers = (List<Document>) bson.get("servers");
        //可以添加多个节点
        //https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html
        if(servers != null) {
            for(Document server : servers) {
                String host = server.getString("host");
                InetAddress tcp_host = null;
                try{
                    tcp_host = InetAddress.getByName(host);
                }
                catch (UnknownHostException ex){
                    ex.printStackTrace();
                }
                Integer port = server.getInteger("port");
                if(host!=null && port!=null) {
                    String msg = "[setTransportAddress] host = " + host + " , port = " + port;
                    esClient.addTransportAddress(new InetSocketTransportAddress(tcp_host, port));
                    System.out.println(msg);
                    logger.info(msg);
                }
            }
        }
        else{
            logger.warn("No Elasticsearch Node was specified!\n");
        }
    }

    /*******************************************************************
     *
     * @param filePath
     * @return
     */
    public static TransportClient getTransportClientStatic(String filePath) {
        String json = FileToolkit.readStringFromFile(filePath);
        Document bson = Document.parse(json);
        String cname = bson.getString("cluster_name");
        logger.info("[cluster_name] = {}", cname);
        if(cname == null){
            logger.warn("No Elasticsearch cluster name was specified!\n");
        }
        Settings settings = Settings.settingsBuilder()
                .put("cluster.name" , cname)
                .put("client.transport.sniff", true)  //sniff other nodes
                .build();
        TransportClient esClient = TransportClient.builder().settings(settings).build();;
        setTransportAddressStatic(esClient, filePath);
        return esClient;
    }




    /**
     * Main FUNC
     * @param args
     */
    public static void  main(String[] args){
        //ElasticSearchDao dao = new ElasticSearchDao("debug");
        String tcpPath = "/elastic_admin/tcp_servers.json";
        ElasticAdministratorTransHelper adminClient = new ElasticAdministratorTransHelper(tcpPath);
        String index = "test_index";
        String alias = "test_meizi";
        //adminClient.createIndex(index);
        //adminClient.closeIndex(index);
        //adminClient.openIndex(index);
        //adminClient.aliasIndex(index, alias);
        adminClient.closeIndex(index);
        String analysisPath = "/elasticsearch/analysis_v1.6.json";
        adminClient.setAnalysis(index, analysisPath);
        adminClient.openIndex(index);
    }

}
